<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html class="dj_gecko" xmlns:v="urn:schemas-microsoft-com:vml" xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

	<title>Google Earth Browser Plugin using ArcGIS Geoprocessing | Site Selection</title>
	<link rel=stylesheet href='samples.css' type='text/css' />

<!-- This demo application is designed to demonstrate how the Google Earth API and the ESRI JavaScript API can work together to make a compelling GIS; utilizing the strengths of each platform. The demo is a direct modification of the demo provided by ESRI to demonstrate the JavaScript API, however this application replaces the ESRI map with an embedded version of Google Earth.-->
		
<!-- First we need to set up our Google Maps API Key which will allow us to utilize the Google Maps and Earth APIs on our site. You will need a key specific you your URL -->
<script src="http://maps.google.com/jsapi?key=ABQIAAAAAIG-SYZUT2gO68AJpyqKhhSKX7xcyV-yfkWcdoh57rA15mTUTBQqiftC7xaUdwkdnopoGz1LrLOMqQ" type="text/javascript"></script>

<!--  We will call another JavaScript which has some functions for turning KML into other geometries, this is an open-ended extension and could use some community work to help finish it out for all to use -->
<script type="text/javascript" src="kmltogeom.js"></script>

<!-- Now we will call a JavaScript that has some functions for the Earth API to help maniuplate the camera--> 
<script type="text/javascript" src="camera.js"></script>

<!-- Now we will call a JavaScript that has some functions that will help translate ESRI Geometries into KML - this is open-eneded too, and could use some community work to help finish it out. The ESRI JS API does have the ability to return KML, but if you are not able to define the tasks on that server, you will not be able to stylize the KML the way that you wish for your application, so it makes sense to only deal with ESRI JSON objects and stylize them on the client side for the most control. This is also a useful approach for when you need to build applications with multiple geoprocessing tasks, because you can keep the ESRI JSON Objects in memory, associated with the KML you are displaying, and pass the geometries back and forth to the ESRI JS API without having to rencode KML geometries into ESRI JSON.  -->
<script type="text/javascript" src="esritokml.js"></script>

<!-- Now we will call the ESRI Google Maps API  -->
<script src="http://serverapi.arcgisonline.com/jsapi/gmaps/?v=1.1" type="text/javascript" ></script>

<!-- Now we will call the ESRI JavaScript API which will allow us to utilise the ESRI Geoprocessing Server -->
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>

<script language=javascript type='text/javascript'>

function hidediv() {
	//this function is used to hide the div that shows a progressbar on screen durring geoprocessing tasks
	if (document.getElementById) { // DOM3 = IE5, NS6
		document.getElementById('hideshow').style.visibility = 'hidden';
	}
	else {
	if (document.layers) { // Netscape 4
		document.hideshow.visibility = 'hidden';
	}
	else { // IE 4
		document.all.hideshow.style.visibility = 'hidden';
	}
	}
}

function showdiv() {
	//this function is used to show the div that shows a progressbar on screen durring geoprocessing tasks
	if (document.getElementById) { // DOM3 = IE5, NS6
		document.getElementById('hideshow').style.visibility = 'visible';
	}
	else {
	if (document.layers) { // Netscape 4
		document.hideshow.visibility = 'visible';
	}
	else { // IE 4
		document.all.hideshow.style.visibility = 'visible';
	}
	}
}
</script> 

  
<script type="text/javascript">
  google.load("earth", "1");
  google.load("maps", "2.99");  // For JS geocoder
  
  //application specific variables
  var ge = null;
  var geocoder;
  var click = new Boolean(false);
  var driveTimes = {};
  var ESRIKML = null; 
  var TargetPlacemark = null;
  var ESRIPOLY = null;
  var gp, featureSet;
  var features = null;
  var chartFeatures = null;
  var ringName = null;
  var Ring1, Ring2, Ring3, CBox, censusBlock = null;
  
  //required to connect ESRI APIS
  dojo.require("esri.tasks.gp");
  dojo.require("esri.tasks.query");
  var queryTask, query;
  
function init() {
  //When the applications starts up, hide the progressbar div
  hidediv();
  //Set the ESRI Geoprocessing Variables which will be used to run Querys and Tasks on the ESRI Server
  geocoder = new GClientGeocoder();
  gp = new esri.tasks.Geoprocessor("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Network/ESRI_DriveTime_US/GPServer/CreateDriveTimePolygons");
  queryTask = new esri.tasks.QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query"); 
  
  // !!!!!!! Important - This application will require passing large geometries back and forth to the ESRI server, which will exceed the charecter limit of URLs on the browser you're running the application in. So, something needs to be in place to act as a proxy between the server you are running the application on and the ESRI server - that is why this application is running inside of Tomcat, and not simply under Apache, ESRI supplies a Proxy JSP which is called here.
  esriConfig.defaults.io.proxyUrl = "proxy.jsp";
       
  query = new esri.tasks.Query();
  query.spatialRelationship = esri.tasks.Query.SPATIAL_REL_INTERSECTS;
  query.outFields = ["NAME", "WHITE", "BLACK", "ASIAN", "HISPANIC", "OTHER", "AGE_UNDER5", "AGE_5_17", "AGE_18_21", "AGE_22_29", "AGE_30_39", "AGE_40_49", "AGE_50_64", "AGE_65_UP", "MALES", "FEMALES"];
  query.returnGeometry = "true";
  //Now that the ESRI settings are set, the application needs to initiate the Google Earth API.   
  google.earth.createInstance("map3d", initCB, failureCB);    
      
}

function initCB(object) {
  //This creates the Google Earth API instance, and defines what layers are turned on and where the Earth will zoom to by default (In this case a Bounding Box around the National Mall in Washington, D.C.
  ge = object;
  ge.getWindow().setVisibility(true);
  ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true); 

  var y1 = 38.881231;
  var x1 = -77.059092;
  var y2 =   38.896299;
  var x2 = -77.000836;
  ge.getView().setAbstractView(createCameraFromRectangle(ge, y1, x1, y2, x2));
  ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
  
  // listen to the click event on the globe and window
  google.earth.addEventListener(ge.getGlobe(), 'mousedown', eventHandler);
  google.earth.addEventListener(ge.getWindow(), 'mousedown', eventHandler);
}

function locatepoint()
  //This is a switch which modifys what happens the Earth window is clicked.
     {
        click = true;
     }
     
function clearlayers(){
  //This function clears whatever KML has been loaded onto the Earth in the appliation.
 
      if (Ring1 != null) {  
      
      ge.getFeatures().removeChild(Ring1);
      ge.getFeatures().removeChild(Ring2);
      ge.getFeatures().removeChild(Ring3);
      ge.getFeatures().removeChild(CBox);
      } 
       
}
 

function eventHandler(event) {
 //This function handles what happens when the Globe is clicked, and if the user has clicked the "Locate" button to indicate that they want to initiate the first Geoprocessing task, the ESRI Drive-Time Polygon task. It will take the Lat / Long of the event click on the Earth, and use that point to create an ESRI Point geometry, and use that point to run the task. When the task is finished, this function will fire the getDriveTimePolys function to handle the results.
 		      
	if (click == true){
			
		clearlayers();      
		var pointSymbol = new esri.symbol.SimpleMarkerSymbol();
		pointSymbol.setOutline = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255,0,0]), 1);
		pointSymbol.setSize(5);
		pointSymbol.setColor(new dojo.Color([0,255,0,0.25]));
		
		
		var GEgeom = new esri.geometry.Point(event.getLongitude(), event.getLatitude(), new esri.SpatialReference({ wkid: 4326 }));
		var graphic = new esri.Graphic(GEgeom,pointSymbol);
		
		
		var driveTimes = dojo.byId("boxDT").value;
		
		var features= [];
		features.push(graphic);
		var featureSet = new esri.tasks.FeatureSet();
		featureSet.features = features;
		var params = { "Input_Location":featureSet, "Drive_Times":driveTimes };
		
		gp.execute(params, getDriveTimePolys);
		
		showdiv();
		
		click = false;
	}
	
	// Prevent default balloon from popping up for marker placemarks as we will be filling the balloons with our own 
	event.preventDefault(); 

}
    
    
function getDriveTimePolys(results,messages) {
 //This function gets the results (the 3 Polygons returned from the ESRI task, keeps them in memory, but also sepeartes each ring and creates seperately stylized KML.
	      
		  features = results[0].value.features;
		  
		  Ring1 = ge.createPlacemark('');
	      Ring1.setGeometry(esrigeomtokml(features[2].geometry, 500, ge.ALTITUDE_RELATIVE_TO_GROUND, 'false', 'true'));
		  ge.getFeatures().appendChild(Ring1);		  
		 
         	  
		  Ring2 = ge.createPlacemark('');
		  Ring2.setGeometry(esrigeomtokml(features[1].geometry, 300, ge.ALTITUDE_RELATIVE_TO_GROUND, 'false', 'true'));
		  ge.getFeatures().appendChild(Ring2);
		  
		  		  
		  Ring3 = ge.createPlacemark('');
		  Ring3.setGeometry(esrigeomtokml(features[0].geometry, 200, ge.ALTITUDE_RELATIVE_TO_GROUND, 'false', 'true'));
		  ge.getFeatures().appendChild(Ring3);
		  
		  
		  colorRings();
			
			

 //now zoom to the extents of the longest drive-time ring
		 ge.getView().setAbstractView(createCameraFromRectangle(ge, features[0].geometry.getExtent().ymin, features[0].geometry.getExtent().xmin, features[0].geometry.getExtent().ymax, features[0].geometry.getExtent().xmax));
		 
		 
 //We need to set event listners on all of the rings so that we can control what happens when the users click on the rings.		 
		  google.earth.addEventListener(Ring1, 'click', RingClick);
		  google.earth.addEventListener(Ring2, 'click', RingClick);
		  google.earth.addEventListener(Ring3, 'click', RingClick);
		  	 
		 hidediv();
}
    
    
function RingClick(event){
//First get the name of the ring that is clicked, and use that to determine which ESRI Polygon still in memory is used for the second phase geoprocessing task which is a query that will intersect the ring with the US Census Blocks data loaded on the ESRI Server and will then visualize the demographics of those blocks using the Google Charts API. 
 
 colorRings();
 
 ringName = event.getTarget().getName();
 
 
  if (ringName == 'Ring1' ){
  
  	highlightRing(Ring1);
  	QueryFromRings(features[2].geometry);
  
  }else if (ringName == 'Ring2' ){
 	
 	highlightRing(Ring2);
 	QueryFromRings(features[1].geometry);
 
  }else if (ringName == 'Ring3' ){
  
  	highlightRing(Ring3);
  	QueryFromRings(features[0].geometry);
 
  } 
 
 }
 
function colorRings(){
 //This function will apply KML styling to the Rings, and update settings such as the Ring Names and Description
  
  var poly1 = ge.createStyle('');
  var polyColor1 = poly1.getPolyStyle().getColor();
  polyColor1.set('66990000');
  //now set the outline size and color
  var lineStyle = poly1.getLineStyle();
  lineStyle.setWidth(lineStyle.getWidth() + 1);
  lineStyle.getColor().set('66990000');
  Ring1.setStyleSelector(poly1);
  Ring1.setName('Ring1');
  Ring1.setDescription('Drive Ring 1');

  var poly2 = ge.createStyle('');
  var polyColor2 = poly2.getPolyStyle().getColor();
  polyColor2.set('6600CC00');
  //now set the outline size and color
  var lineStyle = poly2.getLineStyle();
  lineStyle.setWidth(lineStyle.getWidth() + 1);
  lineStyle.getColor().set('6600CC00');
  Ring2.setStyleSelector(poly2);
  Ring2.setName('Ring2');
  Ring2.setDescription('Drive Ring 2');
  
  var poly3 = ge.createStyle('');
  var polyColor = poly3.getPolyStyle().getColor();
  polyColor.set('660000ff');
  //now set the outline size and color
  var lineStyle = poly3.getLineStyle();
  lineStyle.setWidth(lineStyle.getWidth() + 1);
  lineStyle.getColor().set('660000ff');
  Ring3.setStyleSelector(poly3);
  Ring3.setName('Ring3');
  Ring3.setDescription('Drive Ring 3');
} 
  
  
function highlightRing(ringname){
 //This function will "highlight" a selected polygon in a light blue to show which polygon ring was clicked on for the seond phase of the query.
	var poly0 = ge.createStyle('');
	var polyColor0 = poly0.getPolyStyle().getColor();
	polyColor0.set('99ffff00');
	//now set the outline size and color
	var lineStyle = poly0.getLineStyle();
	lineStyle.setWidth(lineStyle.getWidth() + 3);
	lineStyle.getColor().set('ffffff00');
	ringname.setStyleSelector(poly0);
	ringname.setDescription('Selected Ring');
}  


  
function QueryFromRings(ringgeometry){
 //This function will take the selected Ring, and use the associated ESRI geometry in memory to run the second Geoprocessing task. The result (the interesected Census Blocks, will be added to the earth, and the data visuzlied by the getChart function. 
 showdiv();
 query.geometry = ringgeometry;
 query.geometry.spatialReference = new esri.SpatialReference({ wkid: 4326 });
 queryTask.execute(query, getChart);
}
    
function getChart(featureSet){
 //This function will aggregate the demographic data of the census blocks and create Pie Charts for the data on the fly using the Google Chart API
   chartFeatures = featureSet.features;
   if (CBox != null) {  
	   ge.getFeatures().removeChild(CBox);
   }   
   
	var feature, attributes, males = 0, females = 0, white = 0, black = 0, asian = 0, hispanic = 0, other= 0, gendertotal = 0, racetotal = 0, agetotal = 0, AGE_UNDER5 = 0, AGE_5_17 = 0, AGE_18_21 = 0, AGE_22_29 = 0, AGE_30_39 = 0, AGE_40_49 = 0, AGE_50_64 = 0, AGE_65_UP = 0, graphic;
	var polys = new esri.geometry.Polygon();
	CBox = ge.createFolder('');

	for (var i=0; i<chartFeatures.length; i++) {
		feature = chartFeatures[i];
		attributes = feature.attributes;

		//pie chart gender
		males += parseInt(attributes.MALES);
		females += parseInt(attributes.FEMALES);
		
		//pie chart age
		AGE_UNDER5 += parseInt(attributes.AGE_UNDER5);
		AGE_5_17 += parseInt(attributes.AGE_5_17);
		AGE_18_21 += parseInt(attributes.AGE_18_21);
		AGE_22_29 += parseInt(attributes.AGE_22_29);
		AGE_30_39 += parseInt(attributes.AGE_30_39);
		AGE_40_49 += parseInt(attributes.AGE_40_49);
		AGE_50_64 += parseInt(attributes.AGE_50_64);
		AGE_65_UP += parseInt(attributes.AGE_65_UP);
		
		//create the blockgroup polygon geometry
		var featureGeom = feature.geometry;
		for (var k = 0, kl = featureGeom.rings.length; k < kl; k++) {
	
			var featureGeomRing = featureGeom.rings[k];
			polys.addRing(featureGeomRing);
		}

		censusBlock = ge.createPlacemark('');
		censusBlock.setGeometry(esrigeomtokml(polys, 60, ge.ALTITUDE_RELATIVE_TO_GROUND, 'false', 'true'));
		var poly4 = ge.createStyle('');
		var polyColor = poly4.getPolyStyle().getColor();
		polyColor.set('66ff00ff');
		//now set the outline size and color
		var lineStyle = poly4.getLineStyle();
		lineStyle.setWidth(lineStyle.getWidth() + 1);
		lineStyle.getColor().set('b8ff00ff');
		censusBlock.setStyleSelector(poly4);
		CBox.getFeatures().appendChild(censusBlock);
	}

	ge.getFeatures().appendChild(CBox);


	//pie chart gender
	gendertotal =  males + females;
	males = (males / gendertotal) * 100;
	females = (females / gendertotal) * 100;

	//pie chart age
	agetotal = AGE_UNDER5 + AGE_5_17 + AGE_18_21 + AGE_22_29 + AGE_30_39 + AGE_40_49 + AGE_50_64 + AGE_65_UP;
	AGE_UNDER5 = (AGE_UNDER5 / agetotal) * 100;
	AGE_5_17 = (AGE_5_17 / agetotal) * 100;
	AGE_18_21 = (AGE_18_21 / agetotal) * 100;
	AGE_22_29 = (AGE_22_29 / agetotal) * 100;
	AGE_30_39 = (AGE_30_39 / agetotal) * 100;
	AGE_40_49 = (AGE_40_49 / agetotal) * 100;
	AGE_50_64 = (AGE_50_64 / agetotal) * 100;
	AGE_65_UP = (AGE_65_UP / agetotal) * 100;
	

	///apply these results to Google Chart Objects in the selected rings' Description. 
	var balloon = ge.createFeatureBalloon('');


	if (ringName == 'Ring1' ){
	
		Ring1.setDescription('Gender: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + males + ',' + females + '&chs=320x100&chl=Males|Females&chco=0000FF"> </br> Age Groups: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + AGE_UNDER5 + ',' + AGE_5_17 + ',' + AGE_18_21 + ',' + AGE_22_29 + ',' + AGE_30_39 + ',' + AGE_40_49 + ',' + AGE_50_64 + ',' + AGE_65_UP + '&chs=320x100&chl=Under 5|5-17|18-21|22-29|30-39|40-49|50-64|65 And Older&chco=0000FF"> ');
	
		balloon.setFeature(Ring1);
	
	
	
	}else if (ringName == 'Ring2' ){
	
		Ring2.setDescription('Gender: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + males + ',' + females + '&chs=320x100&chl=Males|Females&chco=00FF00"> </br> Age Groups: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + AGE_UNDER5 + ',' + AGE_5_17 + ',' + AGE_18_21 + ',' + AGE_22_29 + ',' + AGE_30_39 + ',' + AGE_40_49 + ',' + AGE_50_64 + ',' + AGE_65_UP + '&chs=320x100&chl=Under 5|5-17|18-21|22-29|30-39|40-49|50-64|65 And Older&chco=00FF00"> ');
	
		balloon.setFeature(Ring2);
	
	
	}else if (ringName == 'Ring3' ){
	
		Ring3.setDescription('Gender: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + males + ',' + females + '&chs=320x100&chl=Males|Females&chco=FF0000"> </br> Age Groups: </br> <img src="http://chart.apis.google.com/chart?cht=p3&chd=t:' + AGE_UNDER5 + ',' + AGE_5_17 + ',' + AGE_18_21 + ',' + AGE_22_29 + ',' + AGE_30_39 + ',' + AGE_40_49 + ',' + AGE_50_64 + ',' + AGE_65_UP + '&chs=320x100&chl=Under 5|5-17|18-21|22-29|30-39|40-49|50-64|65 And Older&chco=FF0000"> ');
	
		balloon.setFeature(Ring3);
	
	}     
	
	ge.setBalloon(balloon);
	hidediv();
}


function finished(object) {
 //This function fires when KML is returned. It validates the KML and loads it to the Earth.
	hidediv();

	if (!object) {
		alert('bad or NULL kml');
		return;
	}

	if (ESRIKML != null) {  
		ge.getFeatures().removeChild(ESRIKML);
	}  
	
	ESRIKML = object;
	traverseKml(ESRIKML);
	ge.getFeatures().appendChild(ESRIKML);
}

 
 
function failureCB(object) {
 //Alerts if the Earth API did not load correctly
  alert('load failed');
}



function submitLocation() {
 //This function is a generic funtion for handling Geocoding from Google using the Maps API, and will zoom the camera to a specificed height above the returned point.
	var address = document.getElementById('address').value;
	geocoder.getLatLng(
		address, 
		function(point) {
			if (point && ge != null) {
				var la = ge.createLookAt('');     
				la.set(point.y, point.x, 100, ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 0, 4000);
				ge.getView().setAbstractView(la);
				var GEgeom = new esri.geometry.Point(point.x, point.y, new esri.SpatialReference({ wkid: 4326 }));
			}
		}
	);
}



</script>
  
	<style type="text/css">
			@import "http://serverapi.arcgisonline.com/jsapi/arcgis/1/js/dojo/dijit/themes/tundra/tundra.css";
		</style>
  
        <link rel="STYLESHEET" type="text/css" href="index_files/demo_site_selection.css"> 
        

</head> 
<body onload='init()' id='body' style="height:100%">
		<div id="demo_banner"><img src="index_files/banner_jsapi2.png"></div>


		<!-- DEMO PLAYGROUND 														-->
		<div id="demo_playground"> 


			<!-- DEMO HEADER 														-->
			<div id="demo_header">

				<!-- DEMO TITLEBAR													-->
				<div id="header_titlebar">
					<!-- DEMO TITLE 												-->
					<h1>Site Selection and Trade Area Analysis</h1>


				</div> <!-- CLOSES DEMO_TITLEBAR 									-->
				
				<div id="hideshow">
					<center><h2>Geoprocessing....</h2><img src="images/ajax-loader.gif"></center>
		        </div> 

			</div> <!-- CLOSES DEMO_HEADER	 										-->
			
			

			<!-- MAP HOLDER 														-->
		<div id="map_holder">

				<!-- MAP 															-->
				<!-- <div id="map"></div> -->
			
		<div id='map3d_container'>
          		<div id='map3d'></div>
       	</div>
       	</div>
 


<center>

<table width="95%">
<tr>
	<td valign="middle" align="center"">
   	<form name='searchform' id='searchform' action='javascript:submitLocation();void(0);'>
     	 <input type=text size=60 id='address'></input>
    	  <input type=submit value='Go to location'>
   	 </form>
	</td>


	<td>					
					Step 1: Select Drive Times
					<select id="boxDT" onchange="">
							<option value="1 3 5">1, 3, 5 </option>
							<option value="3 6 9">3, 6, 9</option>
							<option value="1 5 10">1, 5, 10</option>
					</select>

					Minutes 
	</td>
				
</tr>
<tr>
				
	
	<td>
			<center><button onclick="clearlayers();">Clear Layers</button></center>
	</td>
	
	<td>
					Step 2: Locate Your Site,  Click&nbsp;&nbsp;<button onclick="locatepoint();">Locate</button>, then click on the Earth. 
	<td/>
</tr>  			
</table>        			
</center>
</div>


    
		       	

		      <!-- Copyright 														--> 
            <a href="http://www.esri.com/legal/copyright-trademarks.html" class="left" id="copyright" target="_blank">Copyright © ESRI</a>  
		
        <!-- Powered by emblem 														--> 
             <a href="http://www.esri.com/" title="ESRI home page" target="_blank"><img src="index_files/poweredby.gif" class="right" id="emblem" height="37" width="77"></a>
            
	  </div></body></html>			